package com.qd.system.importexcel.station;

import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.cdqidi.dto.BatchResult;
import com.cdqidi.excel.domain.ExcelRowMsg;
import com.cdqidi.excel.domain.ImportErr;
import com.cdqidi.excel.util.ExcelUtil;
import com.cdqidi.exception.ExcelOperatorException;
import com.cdqidi.util.ValidatorUtil;
import com.cdqidi.valid.group.DefaultGroup;
import com.qd.common.sys.domain.entity.station.PersonStationOrgDTO;
import com.qd.system.model.PersonStationOrg;
import com.qd.system.service.dict.MbUtil;
import com.qd.system.service.org.OrgService;
import com.qd.system.service.person.PersonService;
import com.qd.system.service.station.PersonStationOrgService;
import com.qd.system.service.station.StationSetService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import javax.validation.ConstraintViolationException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static java.util.stream.Collectors.toList;

/**
 * 人员岗位组织,excel导入处理类
 *
 * @author sjk
 */
@Slf4j
@RequiredArgsConstructor
public class PersonStationOrgImportHandler {

    private final PersonStationOrgService personStationOrgService;
    private final ValidatorUtil validatorUtil;
    private final List<ImportErr> errorList;
    private final OrgService orgService;
    private final PersonService personService;
    private final StationSetService stationSetService;

    private final LocalDateTime now = LocalDateTime.now();

    /**
     * 处理具体导入
     *
     * @param rowList excel行数据集合，默认为1000行
     * @param results 异常信息存储
     */
    public void process(List<ExcelRowMsg<PersonStationOrgDTO>> rowList, List<BatchResult> results) {
        final List<PersonStationOrgDTO> personStationOrgList = rowList.stream().map(ExcelRowMsg::getRowData).collect(toList());
        final List<String> orgIds = personStationOrgList.stream().map(PersonStationOrgDTO::getOrgId).filter(StringUtils::hasLength).collect(toList());
        final List<String> stationIds = personStationOrgList.stream().map(PersonStationOrgDTO::getStationId).filter(StringUtils::hasLength).collect(toList());
        final List<String> personIds = personStationOrgList.stream().map(PersonStationOrgDTO::getPersonId).filter(StringUtils::hasLength).collect(toList());
        final List<String> existsOrgIds = orgService.getBaseMapper().getIds(orgIds);
        final List<String> existsStationIds = stationSetService.getBaseMapper().getIds(stationIds);
        final List<String> existsPersonIds = personService.getBaseMapper().getIds(personIds);
        final List<PersonStationOrg> existsPersonStationOrgIds = existsPersonStationOrgIds(existsStationIds, existsOrgIds, existsPersonIds);
        final List<String> existsIds = existsIds(personStationOrgList);
        final int size = rowList.size();
        try {
            for (ExcelRowMsg<PersonStationOrgDTO> excelRowMsg : rowList) {
                final List<String> errors = new ArrayList<>();
                final PersonStationOrgDTO personStationOrgDTO = excelRowMsg.getRowData();
                final ReadRowHolder readRowHolder = excelRowMsg.getReadRowHolder();
                if (null == personStationOrgDTO.getAddTime()) {
                    personStationOrgDTO.setAddTime(now);
                }
                importValidate(personStationOrgDTO, errors);
                importBaseColumn(personStationOrgDTO, existsOrgIds, existsStationIds, existsPersonIds, existsPersonStationOrgIds, errors);
                if (!errors.isEmpty()) {
                    errorList.add(ExcelUtil.buildError(readRowHolder, errors));
                }
            }
            if (!errorList.isEmpty()) {
                throw new ExcelOperatorException(errorList);
            } else {
                final List<PersonStationOrg> addPersonStationOrgList = new ArrayList<>(size);
                final List<PersonStationOrg> updatePersonStationOrgList = new ArrayList<>(size);
                doProcessDictData(existsIds, personStationOrgList, addPersonStationOrgList, updatePersonStationOrgList);
                BatchResult.buildBatchResult(results, addPersonStationOrgList.size(), updatePersonStationOrgList.size());
                addPersonStationOrgList.clear();
                updatePersonStationOrgList.clear();
            }
        } finally {
            personStationOrgList.clear();
            existsIds.clear();
        }
    }

    private void importBaseColumn(PersonStationOrgDTO personStationOrgDTO, List<String> existsOrgIds, List<String> existsStationIds, List<String> existsPersonIds, List<PersonStationOrg> existsPersonStationOrgIds, List<String> errors) {
        boolean isNotCheck = false;
        if (!MbUtil.isExistInCollection(existsOrgIds, personStationOrgDTO.getOrgId())) {
            errors.add("机构ID不存在[" + personStationOrgDTO.getOrgId() + "]");
            isNotCheck = true;
        }
        if (!MbUtil.isExistInCollection(existsStationIds, personStationOrgDTO.getStationId())) {
            errors.add("职责ID不存在[" + personStationOrgDTO.getStationId() + "]");
            isNotCheck = true;
        }
        if (!MbUtil.isExistInCollection(existsPersonIds, personStationOrgDTO.getPersonId())) {
            errors.add("人员ID不存在[" + personStationOrgDTO.getPersonId() + "]");
            isNotCheck = true;
        }
        if (isNotCheck) {
            return;
        }
        PersonStationOrg personStationOrg = new PersonStationOrg();
        personStationOrg.setPersonId(personStationOrgDTO.getPersonId())
                .setOrgId(personStationOrg.getOrgId())
                .setStationId(personStationOrg.getStationId());
        if (MbUtil.isExistInCollection(existsPersonStationOrgIds, personStationOrg)) {
            errors.add("岗位组织和人员关系已经分配[" + personStationOrgDTO.getStationId() + "|" + personStationOrgDTO.getOrgId() + "|" + personStationOrgDTO.getPersonId() + "]");
        }
    }

    private List<PersonStationOrg> existsPersonStationOrgIds(List<String> stationIds, List<String> orgIds, List<String> personIds) {
        if (stationIds.isEmpty() || orgIds.isEmpty() || personIds.isEmpty()) {
            return Collections.emptyList();
        }
        return personStationOrgService.getBaseMapper().getPersonStationOrgIds(orgIds, stationIds, personIds);
    }

    /**
     * 保存数据
     *
     * @param existsIds                  已经存在的数据库主键
     * @param personStationOrgList       excel行数据集合
     * @param addPersonStationOrgList    添加集合
     * @param updatePersonStationOrgList 更新集合
     */
    private void doProcessDictData(List<String> existsIds, List<PersonStationOrgDTO> personStationOrgList, List<PersonStationOrg> addPersonStationOrgList, List<PersonStationOrg> updatePersonStationOrgList) {
        personStationOrgList.forEach(personStationOrgDTO -> {
            final PersonStationOrg personStationOrg = personStationOrgService.dtoToModel(personStationOrgDTO);
            personStationOrgService.clearCache(personStationOrg);
            if (MbUtil.isExistInCollection(existsIds, personStationOrgDTO.getPersonStationId())) {
                updatePersonStationOrgList.add(personStationOrg);
            } else {
                addPersonStationOrgList.add(personStationOrg);
            }
        });
        if (!addPersonStationOrgList.isEmpty()) {
            personStationOrgService.saveBatch(addPersonStationOrgList);
        }
        if (!updatePersonStationOrgList.isEmpty()) {
            personStationOrgService.updateBatchIds(updatePersonStationOrgList);
        }
    }

    /**
     * 获得主键存在的集合
     *
     * @param personStationOrgList excel行数据集合
     * @return 主键集合
     */
    private List<String> existsIds(List<PersonStationOrgDTO> personStationOrgList) {
        final List<String> ids = personStationOrgList.stream().map(PersonStationOrgDTO::getPersonStationId).collect(toList());
        final List<String> existsIds = personStationOrgService.getBaseMapper().getIds(ids);
        ids.clear();
        return existsIds;
    }

    /**
     * 导入实体验证
     *
     * @param personStationOrgDTO 单个excel行数据
     * @param errors              异常信息存储
     */
    private void importValidate(PersonStationOrgDTO personStationOrgDTO, List<String> errors) {
        if (errors.isEmpty()) {
            try {
                validatorUtil.checkValid(personStationOrgDTO, DefaultGroup.class);
            } catch (ConstraintViolationException e) {
                errors.addAll(validatorUtil.getValidationError(e));
            }
        }
    }
}